#ifndef UUID_38DF025F67564E2EDC8C79A2B9995508
#define UUID_38DF025F67564E2EDC8C79A2B9995508

#include "common.hpp"

struct BitModelCounter
{
	BitModelCounter()
	{
		cnt[0] = 0;
		cnt[1] = 0;
	}

	int p()
	{
		return int((4*4096*uint64(cnt[1]) + 1) / ((cnt[0] + cnt[1]) * 4));
	}

	void update(int y)
	{
		++cnt[y];
	}

	int cnt[2];
};

struct BitModelApproxCounter
{
	static int dt[128];  // i -> 1K/(i+2)

	static void init();

	BitModelApproxCounter()
	: t(1<<31)
	{
	}

	int p()
	{
	#if 0
		int pred = 1 + (t >> 20);
	#else
		int pred = (t >> 20);
		pred += pred == 0;
	#endif
		return pred;
	}

	void update(int y)
	{
	    int n = t&127, p = t>>9;  // count, prediction
		if (n < 127) ++t;
	#if 1
		t += ((y<<23) - p)*dt[n] & 0xffffff80;
	#else
		int maxp = 8388608 - (1<<11);

		unsigned int mask = 0 - y;
		t += ((maxp & mask) - p)*dt[n] & 0xffffff80;
	#endif
	}

	template<typename Coder>
	void encode(Coder& c, int y)
	{
		c.encode(y, p());
		update(y);
	}

	uint32 t;
};

extern BitModelCounter historyCounters[1<<16];

#define BITHISTORYSTATS 0

struct BitModelFast
{
	BitModelFast()
	: prob(1<<11)
#if BITHISTORYSTATS
	, history(0xaa)
#endif
	{
	}

	int p()
	{
		return prob;
	}

	void update(int y)
	{
		unsigned int mask = 0 - y;
		int const shift1 = 5;
		int const correction1 = (1<<(shift1)) - 2;
		prob += int(1 + ((4095 + correction1) & mask) - prob) >> shift1;

#if BITHISTORYSTATS
		history = (history << 1) + y;
#endif
	}

	template<typename Coder>
	void encode(Coder& c, int y)
	{
#if BITHISTORYSTATS
		historyCounters[history].update(y);
#endif
		c.encode(y, prob);
		update(y);
	}

	template<typename Decoder>
	int decode(Decoder& d)
	{
		int y = d.decode(prob);
		update(y);
		return y;
	}

	unsigned short prob;

#if BITHISTORYSTATS
// Extra for stats
	uint16 history;
#endif
};

struct BitModelFast2
{
	BitModelFast2()
	: a(1<<10), b(1<<10)
	{
	}

	int p()
	{
		return a+b;
	}

	void update(int y)
	{
		unsigned int mask = 0 - y;
		int const shift1 = 6;
		int const shift2 = 3;
		int const correction1 = (1<<(shift1)) - 2;
		int const correction2 = (1<<(shift2)) - 2;

		a += int(1 + ((2047 + correction1) & mask) - a) >> shift1;
		b += int(1 + ((2047 + correction2) & mask) - b) >> shift2;
	}

	template<typename Coder>
	void encode(Coder& c, int y)
	{
		c.encode(y, p());
		update(y);
	}

	unsigned short a, b;
};

struct BitModelSmall
{
	BitModelSmall()
	: prob(1<<7)
	{
	}

	int p()
	{
		return (prob << 4) + (1<<3);
	}

	void update(int y)
	{
		unsigned int mask = 0 - y;
		int const shift1 = 3;
		prob += int((255 & mask) - prob) >> shift1;
	}

	template<typename Coder>
	void encode(Coder& c, int y)
	{
		c.encode(y, prob);
		update(y);
	}

	unsigned char prob;
};

#endif // UUID_38DF025F67564E2EDC8C79A2B9995508
